#include <iostream>
#include <string>
#include <queue>
#include <pthread.h>
#include <unistd.h> 
#include <ctime>

const static int defaultcap = 5;

template<typename T>
class blockQueue
{
private:
    bool isFull()
    {
        return _block_queue.size() == _capacity;
    }

    bool isEmpty()
    {
        return _block_queue.empty();
    }
public:
    blockQueue(int capacity = defaultcap)
        :_capacity(capacity)
    {
        pthread_mutex_init(&_mutex, nullptr);
        pthread_cond_init(&_pcond, nullptr);
        pthread_cond_init(&_ccond, nullptr);
    }

    void dequeue(T* out)
    {
        pthread_mutex_lock(&_mutex);
        while (isEmpty())
        {
            pthread_cond_wait(&_ccond, &_mutex);
        }
        *out = _block_queue.front();
        _block_queue.pop();
        pthread_mutex_unlock(&_mutex);
        pthread_cond_signal(&_pcond);
    }

    void enqueue(const T& in)
    {
        pthread_mutex_lock(&_mutex);
        while (isFull())
        {
            pthread_cond_wait(&_pcond, &_mutex);
        }
        _block_queue.push(in);
        pthread_mutex_unlock(&_mutex);
        pthread_cond_signal(&_ccond);
    }

    ~blockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_pcond);
        pthread_cond_destroy(&_ccond);
    }

private:
    std::queue<T> _block_queue; 
    pthread_mutex_t _mutex;
    int _capacity;
    pthread_cond_t _pcond; // 生产者条件变量
    pthread_cond_t _ccond; // 消费者条件变量
};

void *consumer(void *args)
{
    blockQueue<int> *bp = static_cast<blockQueue<int> *>(args);
    while (true)
    {
        // 1. 获取数据
        int i;
        bp->dequeue(&i);

        // 2. 处理数据
        std::cout << "Consumer -> " << i << std::endl;
    }
    
}

void *productor(void *args)
{
    srand(time(nullptr) ^ getpid());
    // blockQueue<Task> *bp = static_cast<blockQueue<Task> *>(args);
    blockQueue<int> *bp = static_cast<blockQueue<int> *>(args);
    int i = 1;
    int n = 10000;
    while (i < n)
    {
        // 1. 构建数据
        bp->enqueue(i);
        std::cout << "productor -> " << i << std::endl;
        i++;
        sleep(1); 
    }
    return nullptr;
}

int main()
{
    // blockQueue<Task> *bp = new blockQueue<Task>();
    blockQueue<int> *bp = new blockQueue<int>();
    pthread_t c1, c2, p1, p2, p3;
    pthread_create(&c1, nullptr, consumer, bp);
    pthread_create(&c2, nullptr, consumer, bp);
    pthread_create(&p1, nullptr, productor, bp);
    pthread_create(&p2, nullptr, productor, bp);
    pthread_create(&p3, nullptr, productor, bp);

    pthread_join(c1, nullptr);
    pthread_join(c2, nullptr);
    pthread_join(p1, nullptr);
    pthread_join(p2, nullptr);
    pthread_join(p3, nullptr);

    return 0;
}

